import { DOCUMENT } from '@angular/common';
import { 
  ApplicationRef, 
  ComponentFactoryResolver, 
  ComponentRef, 
  EmbeddedViewRef, 
  Inject, 
  Injectable, 
  Injector, 
  Type 
} from '@angular/core';

export interface DialogPos {
  top: string;
  left: string;
  width: string;
  height: string;
}

export interface ChildConfig {
  inputs: object;
  outputs: object;
  position?: DialogPos;
}

@Injectable({
  providedIn: 'root'
})
export class DomService {
  private childComponentRef: ComponentRef<any>;
  constructor (
    private resolver: ComponentFactoryResolver,
    private appRef: ApplicationRef,
    private injector: Injector,
    @Inject(DOCUMENT) private document: Document
  ) {}

  public appendComponentTo (
    parentId: string, 
    child: Type<any>,
    childConfig: ChildConfig
  ) {
    // 解析child的组件工厂，并创建子组件实例
    const childComponentRef = this.resolver.
      resolveComponentFactory(child)
      .create(this.injector);
    this.attachConfig(childConfig, childComponentRef);
    this.childComponentRef = childComponentRef;
    // 将子组件实例附加到应用程序引用的视图中
    this.appRef.attachView(childComponentRef.hostView);
    // 获取子组件的根节点
    const childDOMElement = (childComponentRef.hostView as EmbeddedViewRef<any>)
    .rootNodes[0] as HTMLElement;
    // 将子组件的根节点插入父DOM中
    this.document.getElementById(parentId).appendChild(childDOMElement);
  }

  public removeComponent () {
    this.appRef.detachView(this.childComponentRef.hostView);
  }

  public attachConfig (config: ChildConfig, componentRef: ComponentRef<any>) {
    const inputs = config.inputs;
    const outputs = config.outputs;
    for(let key in inputs) {
      if(inputs.hasOwnProperty(key)) {
        const element = inputs[key];
        // componentRef 是组件引用，而 componentRef.instance 是组件实例
        // 作用：设置组件实例的 key 属性为 element 的值
        componentRef.instance[key] = element;
      }
    }
    for(let key in outputs) {
      if(outputs.hasOwnProperty(key)) {
        const element = outputs[key];
        componentRef.instance[key] = element;
      }
    }
  }
}